import { IModuleManager } from './IManager';
import { IsNull, IsNullOrWhiteSpace } from '../TYLibrary/Common/GlobalExtend';
import { TYObject, TYJSONBase } from '../TYLibrary/System/System';
import { ClassRuntimeDecorator, TYPropPrefix } from '../TYLibrary/System/ClassRuntime';
console.log("entitys...");

export var WXXCXCommonClassRuntimeDecorator = (): (target: any) => void => {
    return ClassRuntimeDecorator("WXXCX.Common");
}

/**
 * 授权种类
 *
 * @export
 * @enum {number}
 */
export enum WXAuthType {
    /**
     * 没有权限
     */
    NoAuth = 0,
    /**
     * 拒绝授权
     */
    AuthReject = 1,
    /**
     * 成功授权
     */
    AuthSuccess = 2
}
export enum ADType {
    /**
     * 跳转页面
     */
    Page = "page",
    /**
     * 打开广告页
     */
    OpenAD = "open_ad",
    /**
     * 打开小程序
     */
    OpenMiniProgram = "open_mini_program",
    /**
     * 打开图片
     */
    ShowIMG = "showimg",
    /**
     * 无动作
     */
    NoAction = "no_action"
}
export enum LogType {
    Log = 0,
    Debug = 1,
    Warn = 2,
    Error = 3
}
export enum LogLevel {
    L1 = 0,
    L2 = 1,
    L3 = 2,
    L4 = 3
}
/**
 * 微信登录信息，由平台综合微信接口返回信息提供
 *
 * @export
 * @class WXLoginInfo
 * @extends {TYObject}
 */
@WXXCXCommonClassRuntimeDecorator()
export class WXLoginInfo extends TYObject {
    public PICUrl: string;
    public Name: string;
    public OpenID: string;
    public UnionID: string;
    public AuthSetting: WXAuthType;
}

/* 表对应实体 */
@WXXCXCommonClassRuntimeDecorator()
export class T_USER extends TYObject {
    public ACTIVITY: number;
    public AREA: string;
    public AVATARURL: string;
    public BACKGROUNDURL: string;
    public BIRTHDAY: string;
    public CREATETIME: string;
    public INTRODUCTIONS: string;
    public LASTLOGINTIME: string;
    public LEVEL: number;
    public REFERRALCODE: string;
    public SEX: number;
    public UNIONID: string;
    public OPENID: string;
    public USERNAME: string;
    public VALIDITY: string;
    public ISRECEIVE: boolean;
    public ISAGREE: boolean;
    public ISUPGRADE: boolean;
    public ISNEWUSER: boolean;
    public ISREFEREE: boolean;
}
/**
 *广告
 *
 * @export
 * @class Ad
 * @extends {TYObject}
 */
@WXXCXCommonClassRuntimeDecorator()
export class T_AD extends TYObject {
    public ID: number;
    public OPENTYPE: ADType;
    public OPENPARAMETER: string;
    public ISBANNER: boolean;
    public IMGURL: string;
}
@WXXCXCommonClassRuntimeDecorator()
export class T_ShareInfo extends TYObject {
    public TITLE: string;
    public PATH: string;
    public IMAGEURL: string;
}
/**
 * 常见问题
 * 
 * @export
 * @class T_FAQ
 * @extends {TYObject}
 */
@WXXCXCommonClassRuntimeDecorator()
export class T_FAQ extends TYObject {
    public CONTENT: string;
    public TITLE: string;
    public SORT: number;
}
/**
 * 推荐小程序
 * 
 * @export
 * @class T_MINI_PROGRAM
 * @extends {TYObject}
 */
@WXXCXCommonClassRuntimeDecorator()
export class T_MINI_PROGRAM extends TYObject {
    public APPID: string;
    public NAME: string;
    public DESC: string;
    public PATH: string;
    public LOGO: string;
    public EXTRADATA: string;
    public ENVVERSION: string;
    public SORT: number;
    public IMG: string;
    public ISSHOWIMG: boolean;
}
/**
 * 消息
 *
 * @export
 * @class T_MESSAGE
 * @extends {TYObject}
 */
@WXXCXCommonClassRuntimeDecorator()
export class T_MESSAGE extends TYObject {
    public ID: number;
    public UNIONID: string;
    public CONTENT: string;
    public TYPE: string;
    public CREATETIME: string;
    public ISREAD: boolean;
}

/* 界面绑定的视图 */
/**
 * 显示的广告
 */
@WXXCXCommonClassRuntimeDecorator()
export class V_AD extends T_AD {
    public Programe: WXOpenAPI_NavigateToMiniProgramObj;
    public times: boolean | number;
}

export class _Config {
    // 通用接口
    /**
    *  登入接口
    *
    * @type {string}
    * @memberof _Config
    */
    public TYLogin: string;
    /**
     * 用户登录
     *
     * @type {string}
     * @memberof _Config
     */
    public UserLogin: string;

    /**
     * 常见问题
     *
     * @type {string}
     * @memberof _Config
     */
    public QueryAllFAQ: string;

    /**
     * 获取OpenID
     *
     * @type {string}
     * @memberof _Config
     */
    public GetOpenId: string;

    /**
     * 是否同意协议
     *
     * @type {string}
     * @memberof _Config
     */
    public QueryIsAgree: string;

    /**
     * 获取全部广告
     *
     * @type {string}
     * @memberof _Config
     */
    public QueryAllAD: string;

    /**
     * 推荐小程序
     *
     * @type {string}
     * @memberof _Config
     */
    public QueryMiniProgram: string;

    /**
     * 推荐小程序
     *
     * @type {string}
     * @memberof _Config
     */
    public QueryMiniProgramCount: string;

    /**
     * 获取分享信息
     *
     * @type {string}
     * @memberof _Config
     */
    public GetShareInfo: string;

    /**
     * 保存转发数据
     *
     * @type {string}
     * @memberof _Config
     */
    public AddTRecommend: string;

    /**
     * 查询消息通知
     *
     * @type {string}
     * @memberof _Config
     */
    public QueryAllMessage: string;

    /**
     * 查询未读消息数量
     *
     * @type {string}
     * @memberof _Config
     */
    public QueryNoReadMessageCount: string;

    /**
     * 同意免责声明
     *
     * @type {string}
     * @memberof _Config
     */
    public AgreeAgreement: string;

    /**
     * 领取VIP
     *
     * @type {string}
     * @memberof _Config
     */
    public ReceiveVip: string;

    public Check(): void {
        if (IsNullOrWhiteSpace(this.TYLogin))
            throw "TYConfig.TYLogin属性不能为空！";
        if (IsNullOrWhiteSpace(this.UserLogin))
            throw "TYConfig.TYLogin属性不能为空！";
        if (IsNullOrWhiteSpace(this.GetOpenId))
            throw "TYConfig.TYLogin属性不能为空！";
        if (IsNullOrWhiteSpace(this.AgreeAgreement))
            throw "TYConfig.TYLogin属性不能为空！";
        if (IsNullOrWhiteSpace(this.GetShareInfo))
            throw "TYConfig.TYLogin属性不能为空！";
        if (IsNullOrWhiteSpace(this.QueryIsAgree))
            throw "TYConfig.TYLogin属性不能为空！";
        if (IsNullOrWhiteSpace(this.QueryAllMessage))
            throw "TYConfig.TYLogin属性不能为空！";
        if (IsNullOrWhiteSpace(this.QueryAllAD))
            throw "TYConfig.TYLogin属性不能为空！";
        if (IsNullOrWhiteSpace(this.QueryAllFAQ))
            throw "TYConfig.TYLogin属性不能为空！";
        if (IsNullOrWhiteSpace(this.QueryMiniProgram))
            throw "TYConfig.TYLogin属性不能为空！";
        if (IsNullOrWhiteSpace(this.QueryMiniProgramCount))
            throw "TYConfig.TYLogin属性不能为空！";
        if (IsNullOrWhiteSpace(this.QueryNoReadMessageCount))
            throw "TYConfig.TYLogin属性不能为空！";
        if (IsNullOrWhiteSpace(this.ReceiveVip))
            throw "TYConfig.TYLogin属性不能为空！";
        if (IsNullOrWhiteSpace(this.AddTRecommend))
            throw "TYConfig.TYLogin属性不能为空！";
    }
}
export class _Log {
    public Log(level: LogLevel, ...msg: any[]): void {
        console.log(`${new Date().Format("hh:mm:ss")}【LOG】【${level}】:`, msg);
    }
    public Debug(level: LogLevel, ...msg: any[]): void {
        console.debug(`${new Date().Format("hh:mm:ss")}【Debug】【${level}】:`, msg);
    }
    public Warn(level: LogLevel, ...msg: any[]): void {
        console.warn(`${new Date().Format("hh:mm:ss")}【Warn】【${level}】:`, msg);
    }
    public Error(level: LogLevel, ...msg: any[]): void {
        console.error(`${new Date().Format("hh:mm:ss")}【Error】【${level}】:`, msg);
    }
}

@WXXCXCommonClassRuntimeDecorator()
export class Wx_Application extends TYObject {
    private m_SystemInfo: WXDeviceAPI_SystemInfo = null;

    public IndexPageType: string;
    public AgreementPageType: string;

    public WXLoginInfo: WXLoginInfo = new WXLoginInfo();
    public LaunchData: any = null;
    public ModuleManager: IModuleManager;

    private m_CheckUpdateApp() {
        if (this.SystemInfo.SDKVersion.VersionCompare("1.9.90") < 0)
            return;
        let UpdateManager = wx.getUpdateManager();
        UpdateManager.onUpdateReady(async () => {
            let confirm = await this.Wx_ShowModal('更新提示', '新版本已经准备好，是否重启应用？')
            if (confirm)
                UpdateManager.applyUpdate();
        });
    }

    /**
     * @description 生命周期函数--监听小程序初始化
     * @description 当小程序初始化完成时，会触发 onLaunch（全局只触发一次）
     * 
     * @memberof Wx_Application
     */
    public async onLaunch(options: WXAppAPI_OptionsObj) {
        this.LaunchData = options;
        this.m_CheckUpdateApp();
        if (IsNullOrWhiteSpace(this.IndexPageType))
            throw "App.IndexPageType不能为空！";
        TYConfig.Check();
    }

    /**
     * @description 生命周期函数--监听小程序显示
     * @description 当小程序启动，或从后台进入前台显示，会触发 onShow
     * 
     * @memberof Wx_Application
     */
    public async onShow(options: WXAppAPI_OptionsObj) { }

    /**
     * @description 生命周期函数--监听小程序隐藏
     * @description 当小程序从前台进入后台，会触发 onHide
     * 
     * @memberof Wx_Application
     */
    public async onHide() { }

    /**
     * @description 错误监听函数
     * @description 当小程序发生脚本错误，或者 api 调用失败时，会触发 onError 并带上错误信息
     * 
     * @memberof Wx_Application
     */
    public async onError(msg: string) { }

    /**
     * @description 页面不存在监听函数
     * @description 当小程序出现要打开的页面不存在的情况，会带上页面信息回调该函数，详见下文
     * @description 基础库 1.9.90 开始支持，低版本需做兼容处理
     * @memberof Wx_Application
     */
    public async onPageNotFound(options: WXAppAPI_PageNotFoundObj) { }

    public get SystemInfo(): WXDeviceAPI_SystemInfo {
        if (IsNull(this.m_SystemInfo))
            this.m_SystemInfo = wx.getSystemInfoSync();
        return this.m_SystemInfo;
    }

    public Wx_GetSetting(): Promise<{ [propName in WXScopeType]: boolean }> {
        return new Promise<{ [propName in WXScopeType]: boolean }>((resolve, reject) => {
            try {
                wx.getSetting({
                    success: async (res) => {
                        resolve(res.authSetting);
                    },
                    fail: (e) => {
                        reject(e);
                    }
                })
            }
            catch (e) {
                reject(e);
            }
        });
    }

    public Wx_OpenSetting(): Promise<{ [propName in WXScopeType]: boolean }> {
        return new Promise<{ [propName in WXScopeType]: boolean }>((resolve, reject) => {
            try {
                wx.openSetting({
                    success: async (res) => {
                        resolve(res.authSetting);
                    },
                    fail: (e) => {
                        reject(e);
                    }
                })
            }
            catch (e) {
                reject(e);
            }
        });
    }

    /**
     * 返回值：
     *      true：确定
     *      false：取消
     * 
     * @memberof Wx_Application
     */
    public Wx_ShowModal(
        title: string,
        content: string,
        showCancel: boolean = true,
        cancelText: string = "取消",
        confirmText: string = "确定",
        cancelColor: string = "#000000",
        confirmColor: string = "#3CC51F"): Promise<boolean> {
        return new Promise<boolean>((resolve, reject) => {
            wx.showModal({
                title: title,
                content: content,
                showCancel: showCancel,
                cancelText: cancelText,
                cancelColor: cancelColor,
                confirmText: confirmText,
                confirmColor: confirmColor,
                success: (res) => {
                    if (res.confirm)
                        resolve(true);
                    else
                        resolve(false);
                },
                fail: (res) => {
                    reject(res);
                }
            });
        })
    }

    public Wx_GetShareInfo(shareTicket: string, timeout?: number):
        Promise<{ errMsg: string, encryptedData: string, iv: string }> {
        return new Promise<{ errMsg: string, encryptedData: string, iv: string }>(
            async (resolve, reject) => {
                wx.getShareInfo({
                    shareTicket: shareTicket,
                    timeout: timeout,
                    success: (res) => {
                        resolve(res);
                    },
                    fail: (err) => {
                        reject(err);
                    }
                })
            });
    };

    public SYS_GetNowDate(): Date {
        return new Date();
    }
}

export var WXDataDecorator = (): (target: any) => void => {
    return (target: any): void => {
        let propNames = Object.getOwnPropertyNames(new target());
        propNames = propNames.Where((item) => { return !item.StartWith(TYPropPrefix); });

        propNames.forEach(pName => {
            Object.defineProperty(target.prototype, pName, {
                get: function () {
                    return this[TYPropPrefix + pName];
                },
                set: function (newValue) {
                    this[TYPropPrefix + pName] = newValue;
                    if (IsNull(this.TY__DataChangeList))
                        this.TY__DataChangeList = new Array<string>();
                    this.TY__DataChangeList.push(pName);
                    this.TY__IsEdited = true;
                },
            });
        });
    }
}
export var WXDataClassRuntimeDecorator = (): (target: any) => void => {
    return WXDataDecorator();
}
@WXDataClassRuntimeDecorator()
@WXXCXCommonClassRuntimeDecorator()
export class Wx_PageData extends TYJSONBase {
    public TY__IsEdited:boolean = false;

    /**
     * 授权状态
     *
     * @type {WXAuthType}
     * @memberof Wx_PageData
     */
    public AuthSetting: WXAuthType = WXAuthType.NoAuth;
    /**
     * 页面显示的广告，单个广告
     *
     * @type {V_AD}
     * @memberof Wx_PageData
     */
    public PageAD: V_AD = null;
    /**
     * 页面显示的广告，广告列表
     *
     * @type {Array<V_AD>}
     * @memberof Wx_PageData
     */
    public PageADs: Array<V_AD> = new Array<V_AD>();
    /**
     * 是否能用API跳转小程序,检查小程序基础库版本
     *
     * @type {boolean}
     * @memberof Wx_PageData
     */
    public CanNavigateToMiniProgramForAPI: boolean = false;
    public BarTitle: string = "";

    public LoadData(data: any) {
        if (!IsNull(data)) {
            let propNames = Object.getOwnPropertyNames(data);
            propNames = propNames.Where((item) => { return item.StartWith(TYPropPrefix) && item != "TY__DataChangeList"; });
            propNames.forEach(pName => {
                this[pName.replace(TYPropPrefix, "")] = data[pName];
            });
        }
    }

    public async ApplyChange(page: Wx_Page) {
        if (!IsNull((this as any).TY__DataChangeList) && (this as any).TY__DataChangeList.length > 0) {
            let _data = {};
            (this as any).TY__DataChangeList.forEach(pName => {
                _data[pName] = this[pName];
            });
            (this as any).TY__DataChangeList.Clear();
            await page.__SetData(_data);
        }
    }
}

@WXXCXCommonClassRuntimeDecorator()
export class Wx_Page extends TYObject {
    private m_ShowCount = 0;

    protected m_InitOptions: any;

    private _SetCanNavigateToMiniProgramForAPI(otherV: string): void {
        let r = this.App.SystemInfo.SDKVersion.VersionCompare(otherV) < 0;
        this.Data.CanNavigateToMiniProgramForAPI = r;
    }
    protected async m_App_InitUserInfoAndCheckAuthInfo(sucess?: () => void) {
        try {
            this.App.ModuleManager.AdManager.QueryAllADUrl = TYConfig.QueryAllAD;
            this.App.ModuleManager.AuthManager.TYLoginUrl = TYConfig.TYLogin;
            this.App.ModuleManager.MemberManager.UserLoginUrl = TYConfig.UserLogin;
            this.App.ModuleManager.ShareManager.GetShareInfoUrl = TYConfig.GetShareInfo;
            this.App.ModuleManager.ShareManager.AddTRecommendUrl = TYConfig.AddTRecommend;
            await this.App.ModuleManager.Init();
            if ((!IsNull(this.App.ModuleManager.MemberManager.LoginUser)
                && !IsNullOrWhiteSpace(this.App.ModuleManager.MemberManager.LoginUser.UNIONID))
                || this.App.WXLoginInfo.AuthSetting != WXAuthType.AuthSuccess) {
                if (!IsNull(sucess))
                    sucess();
            }
            else
                await this.__SetData({ LoadFail: true, ErrMessage: '微信服务器账号鉴权失败，请稍候重试' });
        }
        catch (e) {
            if (e.indexOf('request') > -1)
                await this.__SetData({ LoadFail: true, ErrMessage: '由于网络原因导致初始化失败，请检查网络后重试。' });
            else if (e.indexOf('获取服务器数据错误') > -1)
                await this.__SetData({ LoadFail: true, ErrMessage: '由于网络原因导致初始化失败，请检查网络后重试。' });
            else if (e.indexOf('微信鉴权错误') > -1)
                await this.__SetData({ LoadFail: true, ErrMessage: '微信服务器账号鉴权失败，请稍候重试' });
            else
                await this.__SetData({ LoadFail: true, ErrMessage: '由于网络原因导致初始化失败，请检查网络后重试。' });
        }
    }

    public Data: Wx_PageData;

    public App: Wx_Application = null;
    /**
     * @description 生命周期函数--页面加载 
     * @description options:其他页面打开当前页面所调用的 query 参数
     * 
     * @memberof Wx_Page
     */
    public async onLoad(options: any) {
        //console.log("onLoad");
        this.App = getApp() as any;
        this.m_InitOptions = options;
        if (!IsNull(this.Data))
            this.Data.LoadData(this.Data);

        if (!IsNull(this.App.WXLoginInfo) && !IsNull(this.App.WXLoginInfo.AuthSetting))
            this.Data.AuthSetting = this.App.WXLoginInfo.AuthSetting;

        this._SetCanNavigateToMiniProgramForAPI('2.0.7');
        await this.Data.ApplyChange(this);
        this.InitData(options);
    }

    /**
     * 生命周期函数--页面初次渲染完成 
     * 
     * @memberof Wx_Page
     */
    public async onReady() {
        //console.log("onReady");
    }

    /**
     * 生命周期函数--页面显示 
     * 
     * @memberof Wx_Page
     */
    public async onShow() {
        //console.log("onShow");
        this.m_ShowCount++;
        if (this.m_ShowCount > 1)
            await this.onShowAgain();
    }

    public async onShowAgain() {

    }

    /**
     * 生命周期函数--页面隐藏 
     * 
     * @memberof Wx_Page
     */
    public async onHide() {
        //console.log("onHide");
    }

    /**
     * 生命周期函数--页面卸载 
     * 
     * @memberof Wx_Page
     */
    public async onUnload() {
        //console.log("onUnload");
    }

    /**
     * 页面相关事件处理函数--监听用户下拉动作 
     * 
     * @memberof Wx_Page
     */
    public async onPullDownRefresh() { }

    /**
     * 页面上拉触底事件的处理函数 
     * 
     * @memberof Wx_Page
     */
    public async onReachBottom() { }

    /**
     * @description 页面转发事件
     * @description from:转发事件来源。button：页面内转发按钮；menu：右上角转发菜单
     * @description target:如果 from 值是 button，则 target 是触发这次转发事件的 button，否则为 undefined
     * 
     * @description 返回值
     * @description title 转发标题 当前小程序名称  
     * @description path 转发路径 当前页面 path ，必须是以 / 开头的完整路径  
     * @description imageUrl 自定义图片路径，可以是本地文件路径、代码包文件路径或者网络图片路径，支持PNG及JPG，不传入 imageUrl 则使用默认截图。显示图片长宽比是 5:4 
     *
     * @param {{ from: string, target: any }} [options]
     * @returns {{ title?: string, path?: string, imageUrl?: string }}
     * @memberof Wx_Page
     */
    public onShareAppMessage(options?: { from: string, target: any }): { title?: string, path?: string, imageUrl?: string } {
        if (!IsNull(this.App.ModuleManager) && !IsNull(this.App.ModuleManager.ShareManager))
            return this.App.ModuleManager.ShareManager.onShareAppMessage(options);
        else
            return null;
    }

    /**
     * 页面滚动触发事件的处理函数 
     *
     * @param {{ scrollTop: number }} options 页面在垂直方向已滚动的距离（单位px）
     * @memberof Wx_Page
     */
    public async onPageScroll(options: { scrollTop: number }) { }

    /**
     * 当前是 tab 页时，点击 tab 时触发
     *
     * @memberof Wx_Page
     */
    public async onTabItemTap(item: { index: number, pagePath: string, text: string }) { }

    /**
     * 将数据从逻辑层发送到视图层（异步），同时改变对应的  this.data  的值（同步）。
     * 
     * @param {*} data 
     * @param {() => void} callback 
     * @memberof Wx_Page
     */
    public __SetData(data: any): Promise<void> {
        return new Promise<void>((resolve, reject) => {
            try {
                if (this.App.SystemInfo.SDKVersion.VersionCompare("1.5.0") >= 0)
                    (this as any).setData(data, () => { resolve() });
                else {
                    (this as any).setData(data);
                    resolve();
                }
            }
            catch (e) {
                reject(e);
            }
        });
    }

    public async InitData(options: any) { }

    public async ShowError(err: any) {
        return new Promise<void>((resolve, reject) => {
            wx.showModal({
                title: "提示信息",
                content: (err.toString().indexOf("request") > -1 ? "加载失败，请检查网络连接！" : err.toString()),
                showCancel: false,
                success: (res) => {
                    resolve();
                },
                fail: (res) => {
                    resolve();
                }
            });
        });
    }

    public BuildingHandler(e: any): void {
        wx.showModal({
            title: '提示信息',
            content: '此功能正在拼命开发中，敬请期待！',
            showCancel: false
        });
    }

    public CallPhoneHandler(e: any): void {
        if (!IsNullOrWhiteSpace(e.currentTarget.dataset.phone)) {
            const phone = e.currentTarget.dataset.phone;
            wx.makePhoneCall({ phoneNumber: phone })
        }
    }

    /**
    * 判断本地缓存是否存在
    * @param obj 
    */
    public StorageIsNull = (obj: any): boolean => {
        if (typeof obj == 'string')
            return obj.IsNullOrWhiteSpace();
        else
            return IsNull(obj)
    }

    public ADClickHandler(e): void {
        this.App.ModuleManager.AdManager.AdClick(this, e);
    }

    public async BindopenSettingHandler(e) {
        if (!IsNull(e.detail.errMsg)) {
            await this.App.ModuleManager.AuthManager.Refresh();
            if (e.detail.authSetting[WXScopeType.userInfo] == true)
                await this.InitData(this.m_InitOptions);
        }
    }

    public FormIDSubmitHandler(e: any): void {
        let formId: string = e.detail.formId;
        //  console.log(e)
        // console.log('form发生了submit事件，推送码为：', formId)
    }
}

export let TYConfig = new _Config();
export let Logger = new _Log();